/*
 * @Author: wangjun haodreams@163.com
 * @Date: 2024-07-25 14:19:21
 * @LastEditors: wangjun haodreams@163.com
 * @LastEditTime: 2024-07-27 15:57:14
 * @FilePath: \libs\axis\rawspan.go
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
package span

import (
	"errors"
	"math"
)

type Span struct {
	rs    []*TimePoint
	start *TimePoint
	end   *TimePoint
	min   *TimePoint
	max   *TimePoint
	t     int64
}

func NewSpan(t int64) (m *Span) {
	m = new(Span)
	m.t = t
	m.Reset()
	return m
}

func (m *Span) Reset() {
	m.rs = nil
	m.start = nil
	m.end = nil
	m.min = nil
	m.max = nil
}

func (m *Span) Put(x int64, y float64) {
	//log.Println(easy.FormatTime(m.t), easy.FormatTime(x), y)

	tp := new(TimePoint)
	tp.X = x
	tp.Y = y
	m.rs = append(m.rs, tp)
}

func (m *Span) Calc() *Span {
	if len(m.rs) == 0 {
		return m
	}
	m.start = m.rs[0]
	n := len(m.rs) - 1
	for i := 1; i <= n; i++ {
		val := m.rs[i]
		if math.IsNaN(val.Y) || math.IsInf(val.Y, 0) {
			m.end = val
			continue
		}
		if i == n {
			m.end = val
		}
		if m.min == nil || m.max == nil {
			m.min = val
			m.max = val
			continue
		}
		if m.min.Y > val.Y {
			m.min = val
		}
		if m.max.Y < val.Y {
			m.max = val
		}
	}
	return m
}

func (m *Span) Vals(prev float64) (vals []*TimePoint) {
	vals = make([]*TimePoint, 4)
	if len(m.rs) == 0 {
		for i, val := range vals {
			val = new(TimePoint)
			val.Y = prev
			val.X = m.t
			vals[i] = val
		}
		return
	}

	vals[0] = m.start
	if m.max != nil && m.min != nil {
		if m.max.X < m.min.X {
			vals[1] = m.max
			vals[2] = m.min
		} else {
			vals[1] = m.min
			vals[2] = m.max
		}
		vals[3] = m.end
		return
	}
	vals[1] = m.start
	vals[2] = m.start
	if m.end != nil {
		vals[3] = m.end
	} else {
		vals[3] = m.start
	}
	//log.Println(easy.FormatTime(m.t), easy.FormatTime(m.start.X), m.start.Y)
	return
}

type RawSpan struct {
	Error     error
	rs        []*Span
	fvals     []float64
	begin     int64
	end       int64
	interval  int64
	Precision int
}

/**
 * @description: 新建一个扩展填充规则
 * @param {*} begin
 * @param {*} end
 * @param {int64} interval
 * @return {*}
 */
func NewRawSpan(begin, end, interval int64) *RawSpan {
	m := new(RawSpan)
	m.Reset(begin, end, interval)
	return m
}

func (m *RawSpan) GetFVals() []float64 {
	return m.fvals
}

func (m *RawSpan) GetTime(i int) int64 {
	return m.begin + int64(i)*m.interval/4
}

/**
 * @description: 复位，数据结构复用时使用
 * @param {*} begin
 * @param {*} end
 * @param {int64} interval
 * @return {*}
 */
func (m *RawSpan) Reset(begin, end, interval int64) {
	count := end - begin
	if interval > 0 {
		count = count / int64(interval)
	} else {
		interval = 1
	}
	count++
	m.begin = begin
	m.end = end
	m.interval = interval
	if cap(m.rs) < int(count) {
		m.rs = make([]*Span, count)
		m.fvals = make([]float64, count*4)
	} else {
		m.rs = m.rs[:count]
		m.fvals = m.fvals[:count*4]
	}
	t := m.begin
	for i, r := range m.rs {
		if r == nil {
			r = NewSpan(t)
			m.rs[i] = r
		} else {
			r.t = t
			r.Reset()
		}
		t += m.interval
	}
}

/**
 * @description: 存放数据
 * @param {*opdb.Real} value
 * @return {*}
 */
func (m *RawSpan) Put(x int64, y float64) (err error) {
	if x >= m.end {
		err = errors.New("值时间错误")
		return
	}
	if x < m.begin {
		x = m.begin
	}
	idx := x - m.begin

	if m.interval == 1 {
		m.rs[idx].Put(x, y)
	} else {
		idx = idx / m.interval
		m.rs[idx].Put(x, y)
	}
	return nil
}

/**
 * @description: 获取数据数组
 * @return {*}
 */
func (m *RawSpan) Update() *RawSpan {
	prev := math.NaN()
	idx := 0
	for _, span := range m.rs {
		point := span.Calc().Vals(prev)
		for i, val := range point {
			m.fvals[idx] = val.Y
			if i == 3 {
				prev = val.Y
			}
			idx++
		}
	}
	return m
}
